
// Media_PlayerDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Media_Player.h"
#include "Media_PlayerDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CAboutDlg dialog used for App About
UINT ThreadOpenFile(LPVOID pParam)
{
	CMedia_PlayerDlg *pDlg = (CMedia_PlayerDlg*) pParam;
	pDlg->OpenFile();
	return 0;
}

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()


// CMedia_PlayerDlg dialog




CMedia_PlayerDlg::CMedia_PlayerDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CMedia_PlayerDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CMedia_PlayerDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_STC_PLAYING, m_stcPlaying);
	DDX_Control(pDX, IDC_SLD_LIFE, m_SliderTimeLife);
	DDX_Control(pDX, IDC_STC_TIMEPLAY, m_stcTimePlay);
	DDX_Control(pDX, IDC_STC_TIME_TOTAL, m_stcTimeTotal);
	DDX_Control(pDX, IDC_BTN_PLAY, m_btnPlay);
	DDX_Control(pDX, IDC_BTN_STOP, m_btnStop);
	DDX_Control(pDX, IDC_SLD_VOLUME, m_SliderVolume);
}

BEGIN_MESSAGE_MAP(CMedia_PlayerDlg, CDialog)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDC_BTN_PLAY, &CMedia_PlayerDlg::OnBnClickedBtnPlay)
	ON_BN_CLICKED(IDC_BTN_STOP, &CMedia_PlayerDlg::OnBnClickedBtnStop)
	ON_WM_SIZE()
	ON_WM_SIZING()
	ON_WM_TIMER()
	ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_SLD_LIFE, &CMedia_PlayerDlg::OnNMReleasedcaptureSldLife)
	ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_SLD_VOLUME, &CMedia_PlayerDlg::OnNMReleasedcaptureSldVolume)
	ON_COMMAND(ID_FILE_OPEN, &CMedia_PlayerDlg::OnFileOpen)
	ON_COMMAND(ID_FILE_CLOSE, &CMedia_PlayerDlg::OnFileClose)
	ON_COMMAND(ID_CONTROL_PLAY, &CMedia_PlayerDlg::OnControlPlay)
	ON_COMMAND(ID_CONTROL_MUTE, &CMedia_PlayerDlg::OnControlMute)
	ON_COMMAND(ID_ABOUT_ABOUT, &CMedia_PlayerDlg::OnAbout)
	ON_COMMAND(ID_CONTROL_STOP, &CMedia_PlayerDlg::OnControlStop)
END_MESSAGE_MAP()

//BEGIN_EASYSIZE_MAP(CMedia_PlayerDlg)
//	EASYSIZE(IDC_BTN_PLAY, ES_KEEPSIZE, IDC_SLD_LIFE, IDC_BTN_STOP, ES_BORDER, ES_VCENTER)
//	EASYSIZE(IDC_BTN_STOP, IDC_BTN_PLAY, IDC_SLD_LIFE, ES_KEEPSIZE, ES_BORDER, ES_VCENTER)
//	EASYSIZE(IDC_SLD_VOLUME, IDC_BTN_STOP, IDC_SLD_LIFE, ES_KEEPSIZE, ES_BORDER, ES_VCENTER)
//	//EASYSIZE(IDC_STC_TIME_TOTAL, ES_KEEPSIZE, ES_KEEPSIZE, ES_KEEPSIZE, ES_KEEPSIZE, 0)
//	//EASYSIZE(IDC_STC_TIMEPLAY, ES_KEEPSIZE, ES_KEEPSIZE, ES_KEEPSIZE, ES_KEEPSIZE, 0)
//	//EASYSIZE(IDC_SLD_LIFE, ES_BORDER, ES_KEEPSIZE, ES_BORDER, ES_BORDER, 0)
//	/*EASYSIZE(IDC_STC_PLAYING, ES_KEEPSIZE, ES_KEEPSIZE, ES_KEEPSIZE, ES_KEEPSIZE, 0)*/
//	
//END_EASYSIZE_MAP

// CMedia_PlayerDlg message handlers

BOOL CMedia_PlayerDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	m_btnPlay.SetIcon((HICON)LoadImage(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDI_PLAY),IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR));
	m_btnPlay.EnableWindow(FALSE);
	m_btnStop.SetIcon((HICON)LoadImage(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDI_STOP),IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR));
	m_btnStop.EnableWindow(FALSE);

	// TODO: Add extra initialization here
	m_Menu.LoadMenuW(IDR_MENU);
	SetMenu(&m_Menu);
	
	// Initialize DirectShow
	pGB				= NULL;
	pMC				= NULL;
	pMS				= NULL;
	pME				= NULL;
	hOwner			= NULL;
	totalDuration	= 0;
	timeElapsed		= 0;

	m_SliderVolume.SetRange(-10, 0);
	m_SliderVolume.SetPos(-5);
	lVolume = 0;
	m_bInit = FALSE;
	Initialize(this->m_hWnd);
	//INIT_EASYSIZE;
	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CMedia_PlayerDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CMedia_PlayerDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting
		RECT rcClient;
		GetClientRect(&rcClient);
		if(pWc != NULL)
		{
			HRGN rgnClient = CreateRectRgnIndirect(&rcClient);
			HRGN rgnVideo  = CreateRectRgnIndirect(&rcDest);
			CombineRgn(rgnClient, rgnClient, rgnVideo, RGN_DIFF);

			//Paint on Window
			HBRUSH hbr = GetSysColorBrush(COLOR_BTNFACE);
			FillRgn(dc.m_hDC, rgnClient, hbr);
			
			DeleteObject(hbr);
			DeleteObject(rgnClient);
			DeleteObject(rgnVideo);

			//Request the VMR to paint the video.
			HRESULT hr = pWc->RepaintVideo(hwnd, dc.m_hDC);
		}
		else 
		{
			FillRect(dc.m_hDC, &rcClient, (HBRUSH)(COLOR_BTNFACE + 1));
		}
		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CMedia_PlayerDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

void CMedia_PlayerDlg::Initialize(HWND owner)
{
	HRESULT hr;
	hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
	if(FAILED(hr))
	{
		MessageBox(_T("Error ->COM init is fail"));
	}
	//create instace and query interface
	hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,IID_IGraphBuilder, (void **)&pGB);
	if(FAILED(hr))
	{
		MessageBox(_T("Error -> could not create the FilterGraphManager"));
		pGB->Release();
		pGB = NULL;
		CoUninitialize();
	}

	//query interface
	hr = pGB->QueryInterface(IID_IMediaControl, (void **)&pMC);
	hr = pGB->QueryInterface(IID_IMediaSeeking, (void**)&pMS);
	hr = pGB->QueryInterface(IID_IMediaEventEx, (void**)&pME);
	hr = pGB->QueryInterface(IID_IBasicAudio,(void**)&pAudio);

	if (!pMC || !pMS || !pME|| !pAudio)
	{
		MessageBox(_T("Critical error, error getting references Error"));
		pMC->Release();
		pMC = NULL;
		pMS->Release();
		pMS = NULL;
		pME->Release();
		pME = NULL;
		pAudio->Release();
		pAudio= NULL;
	}
	
	hOwner = owner;
	pME->SetNotifyWindow((OAHWND)hOwner, WM_GRAPHNOTIFY, 0);
	isPlaying = FALSE;
	lTotalDuration = 0;
}

int CMedia_PlayerDlg::StartPlayingFile()
{
	//Check whether repeat file
	if(m_bInit)
	{
		ReleaseVal();
		m_bInit = FALSE;
	}
	else
	{
		char totalTime[MAX_SIZE];
		LONGLONG lDuration100NanoSecs = 0;
		HRESULT hr;
		hr = InitWindowlessVMR(AfxGetMainWnd()->m_hWnd, pGB, &pWc);
		pGB->RenderFile((LPCWSTR)m_strPathFile, NULL);
		
		long lWidth, lHeight;
		hr = pWc->GetNativeVideoSize(&lWidth, &lHeight, NULL, NULL);
		if(SUCCEEDED(hr))
		{
			RECT rcSrc, rcDest;
			SetRect(&rcSrc, 0, 0, lWidth, lHeight);
			GetClientRect(&rcDest);
			SetRect(&rcDest, 0, 80, rcDest.right, rcDest.bottom - 170);
			hr = pWc->SetVideoPosition(&rcSrc, &rcDest);
		}

		pMS->GetDuration(&lDuration100NanoSecs);
		totalDuration = (long)(lDuration100NanoSecs/10000000);//10^-7
		step = (float)100/totalDuration;
		sprintf(totalTime, "%02u:%02u:%02u", (totalDuration / 3600) % 60, (totalDuration / 60) % 60, (totalDuration % 60));
		CString strTime(totalTime);
		int sizeOfString2 = (strTime.GetLength() + 1);
		LPTSTR  lpsz2     = new TCHAR[sizeOfString2];
		_tcscpy_s(lpsz2, sizeOfString2, strTime);
		m_stcTimeTotal.SetWindowTextW(lpsz2);

		m_stcPlaying.SetWindowTextW((LPCTSTR)m_strPathFile);
		isPlaying = TRUE;

		m_btnPlay.SetIcon((HICON)LoadImage(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDI_PAUSE),IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR));
		m_btnPlay.EnableWindow(TRUE);
		m_btnStop.EnableWindow(TRUE);

		m_SliderTimeLife.SetRange(0,100);
		SetTimer(MY_TIMEREVENT,1000,(TIMERPROC)NULL);

		// play the file
		pMC->Run();
		hr = pAudio->get_Volume(&lVolume);
		int nValSlider = lVolume / (1000);
		m_SliderVolume.SetPos((int)nValSlider);
		
		m_bInit = TRUE;
	}
	return 1;
}

int CMedia_PlayerDlg::PlayPauseMedia()
{
	if(pMC != NULL)
	{
		if(isPlaying)
		{
			pMC->Pause();
			isPlaying = FALSE;
			m_btnPlay.SetIcon((HICON)LoadImage(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDI_PLAY),IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR));
		}
		else	
		{
			pMC->Run();
			isPlaying = TRUE;
			m_btnPlay.SetIcon((HICON)LoadImage(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDI_PAUSE),IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR));
		}
	}
	return 1;
}

int CMedia_PlayerDlg::DoTimeStuff()
{
	char time[MAX_SIZE] = "";
	int pos = 0;
	if (!isPlaying || timeElapsed >= totalDuration)
	{
		return 0;
	}
	timeElapsed++;
	pos = (int) ((float)step * (float)timeElapsed);
	m_SliderTimeLife.SetPos(pos);

	sprintf(time, "%02u:%02u:%02u", (timeElapsed / 3600) % 60, (timeElapsed / 60) % 60, timeElapsed % 60);
	CString strTime(time);
	int sizeOfString2 = (strTime.GetLength() + 1);
	LPTSTR lpsz2      = new TCHAR[sizeOfString2];
	_tcscpy_s(lpsz2, sizeOfString2, strTime);
	m_stcTimePlay.SetWindowTextW(lpsz2);
	return 1;
}

void CMedia_PlayerDlg::OnTimer(UINT_PTR nIDEvent)
{
	if(nIDEvent == MY_TIMEREVENT)
		DoTimeStuff();
	CDialog::OnTimer(nIDEvent);
}

int CMedia_PlayerDlg::StopMedia()
{
	REFERENCE_TIME rt = 0;
	if(pMC != NULL)
	{
		if(isPlaying)
		{
			pMC->Stop();
			isPlaying = FALSE;
		}
		if(pMS)
		{
			pMS->SetPositions(&rt, AM_SEEKING_AbsolutePositioning,NULL,AM_SEEKING_NoPositioning);
		}
		m_SliderTimeLife.SetPos(0);
		timeElapsed = 0;
		m_stcTimePlay.SetWindowTextW(L"00:00:00");
		m_btnPlay.SetIcon((HICON)LoadImage(AfxGetApp()->m_hInstance, MAKEINTRESOURCE(IDI_PLAY),IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR));
	}
	return 1;
}

BOOL CMedia_PlayerDlg::PreTranslateMessage(MSG *pMsg)
{
	if(pMsg->message == WM_GRAPHNOTIFY)
		HanldeEventFromGraph();
	return CWnd::PreTranslateMessage(pMsg);
}

int CMedia_PlayerDlg::HanldeEventFromGraph()
{
	HRESULT hr = S_OK;
	long evCode, param1, param2;
	if(!pME)
	{
		AfxMessageBox(_T("MediaEventEx interface error"));
		return 0;
	}
	while (SUCCEEDED(pME->GetEvent(&evCode, &param1, &param2, 0)))
	{
		switch(evCode)
		{
			case EC_COMPLETE:
				StopMedia();
			break;	
		}
		hr = pME->FreeEventParams(evCode, param1, param2);
	}
	return 1;
}

int CMedia_PlayerDlg::ReleaseVal()
{
	StopMedia();
	if(pMC)
	{
		pMC->Release();
		pMC = NULL;
	}
	if(pMS)
	{
		pMS->Release();
		pMS = NULL;
	}
	if(pME)
	{
		pME->Release();
		pME = NULL;
	}
	if(pGB)
	{
		pGB->Release();
		pGB = NULL;
	}
	if(pAudio)
	{
		pAudio->Release();
		pAudio = NULL;
	}
	return 1;
}

void CMedia_PlayerDlg::OnBnClickedBtnPlay()
{
	// TODO: Add your control notification handler code here
	PlayPauseMedia();
}

void CMedia_PlayerDlg::OnBnClickedBtnStop()
{
	// TODO: Add your control notification handler code here
	StopMedia();
}

void CMedia_PlayerDlg::OnSize(UINT nType, int cx, int cy)
{
	CDialog::OnSize(nType, cx, cy);
	/*UPDATE_EASYSIZE;*/
	// TODO: Add your message handler code here
}

void CMedia_PlayerDlg::OnSizing(UINT fwSide, LPRECT pRect)
{
	CDialog::OnSizing(fwSide, pRect);
	//EASYSIZE_MINSIZE(800,600,fwSide,pRect);
	// TODO: Add your message handler code here
}

void CMedia_PlayerDlg::OnNMReleasedcaptureSldLife(NMHDR *pNMHDR, LRESULT *pResult)
{
	// TODO: Add your control notification handler code here
	*pResult = 0;
	HRESULT hr;
	int nPos = m_SliderTimeLife.GetPos();
	pMS->GetDuration(&lTotalDuration);
	hr = pMC->Pause();
	REFERENCE_TIME rtNew = (lTotalDuration * nPos) / 100;
	hr = pMS->SetPositions(&rtNew, AM_SEEKING_AbsolutePositioning,
                             NULL,AM_SEEKING_NoPositioning);
	hr = pMS->GetCurrentPosition(&rtNew);
	hr = pMC->Run();
	m_SliderTimeLife.SetPos(rtNew / 10000000);
	timeElapsed = rtNew / 10000000;
	char time[MAX_SIZE] = "";
	sprintf(time, "%02u:%02u:%02u", (timeElapsed / 3600) % 60, (timeElapsed / 60) % 60, timeElapsed % 60);

	CString strTime(time);
	int sizeOfString2 = (strTime.GetLength() + 1);
	LPTSTR lpsz2      = new TCHAR[sizeOfString2];
	_tcscpy_s(lpsz2, sizeOfString2, strTime);
	m_stcTimePlay.SetWindowText(lpsz2);
}

HRESULT CMedia_PlayerDlg::InitWindowlessVMR(HWND hwndApp, IGraphBuilder* pGraph,IVMRWindowlessControl9 **ppWc)
{
	if(!pGraph || !ppWc)
	{
		return E_POINTER;
	}
	IBaseFilter *pVmr = NULL;
	IVMRWindowlessControl9 *pWc = NULL;
	HRESULT hr = CoCreateInstance(CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void**)&pVmr);
	if(FAILED(hr))
	{
		return hr;
	}

	//Add the VMR to the filter graph
	hr = pGraph->AddFilter(pVmr, L"Video Mixing Renderer");
	if(FAILED(hr))
	{
		pVmr->Release();
		return hr;
	}

	//Set the rendering mode
	IVMRFilterConfig9 *pConfig;
	hr = pVmr->QueryInterface(IID_IVMRFilterConfig9, (void**)&pConfig);
	if(SUCCEEDED(hr))
	{
		hr = pConfig->SetRenderingMode(VMR9Mode_Windowless);
		pConfig->Release();
	}
	if(SUCCEEDED(hr))
	{
		hr = pVmr->QueryInterface(IID_IVMRWindowlessControl9, (void**)&pWc);
		if(SUCCEEDED(hr))
		{
			hr = pWc->SetVideoClippingWindow(hwndApp);
			if(SUCCEEDED(hr))
			{
				*ppWc = pWc;
			}
			else
			{
				pWc->Release();
			}
		}
	}
	pVmr->Release();
	return hr;
}

void CMedia_PlayerDlg::OnNMReleasedcaptureSldVolume(NMHDR *pNMHDR, LRESULT *pResult)
{
	// TODO: Add your control notification handler code here
	*pResult = 0;
	int nPos = m_SliderVolume.GetPos();
	HRESULT hr;
	if(nPos > -8)
	{
		int val = 500;
		lVolume = nPos * val;
	}
	else
	{
		int val = 1000;
		lVolume = nPos * val;
	}
	hr = pAudio->put_Volume(lVolume);
}

void CMedia_PlayerDlg::OnFileOpen()
{
	// TODO: Add your command handler code here
	AfxBeginThread(ThreadOpenFile,this);

}
void CMedia_PlayerDlg::OpenFile()
{
    CString strFilter = _T("All files| *.mp3;*.avi;*.wmv;*.*|");
	strFilter += _T("video file (*.avi;*.wmv)|*.avi;*.wmv|");
	strFilter += _T("mp3 file (*.mp3)|*.mp3|");

	CFileDialog Load(TRUE, NULL, NULL, OFN_FILEMUSTEXIST| OFN_HIDEREADONLY |OFN_ALLOWMULTISELECT,strFilter, NULL);
	Load.m_ofn.lpstrTitle= _T("Open Media file");
	if (Load.DoModal() == IDOK) 
	{
		m_strPathFile=Load.GetPathName();
		m_strNameFile=Load.GetFileName();
		StartPlayingFile();
	}
}

void CMedia_PlayerDlg::OnFileClose()
{
	// TODO: Add your command handler code here
	PostQuitMessage(0);
}

void CMedia_PlayerDlg::OnControlPlay()
{
	// TODO: Add your command handler code here
	PlayPauseMedia();
}

void CMedia_PlayerDlg::OnControlMute()
{
	// TODO: Add your command handler code here
	LONG g_lVolume;
	HRESULT	hr = pAudio->get_Volume(&g_lVolume);
	if (g_lVolume > VOLUME_SILENCE)
        g_lVolume = VOLUME_SILENCE;
    else
        g_lVolume = lVolume;
	hr = pAudio->put_Volume(g_lVolume);
}

void CMedia_PlayerDlg::OnAbout()
{
	// TODO: Add your command handler code here
}

void CMedia_PlayerDlg::OnControlStop()
{
	// TODO: Add your command handler code here
	StopMedia();
}
